#include <iostream>
#include <windows.h>
#include <time.h>
#include <conio.h>
#include <queue>

struct coordinate {
	int x;
	int y;
};

int map[lengthofside][lengthofside], orientation, game_over, speed_change, last_orient;
int refresh_interval, tip_interval;
const int default_interval=4000;
deque<coordinate> snake;



void place_food() {
	int x, y;
	srand(time(0));
	while (1) {
		x = rand() % (lengthofside - 2) + 1;
		y = rand() % (lengthofside - 2) + 1;
		if (map[x][y] == 0) {
			map[x][y] = 1;
			break;
		}
	}
	return;
}

void init() {
	speed_change = 0;
	tip_interval = 0;
	game_over = 0;
	memset(map, 0, sizeof(map));
	score = 0;
	base_score = 3;
	orientation = 1;
	snake.clear();
	refresh_interval = default_interval;
	snake.push_back({ 15,10 }), snake.push_back({ 16,10 }), snake.push_back({ 17,10 });
	map[15][10] = 2, map[16][10] = 3, map[17][10] = 3;
	
	setColor(15);
	system("cls");
	HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
	CONSOLE_CURSOR_INFO cursorInfo;
	GetConsoleCursorInfo(hConsole, &cursorInfo);
	cursorInfo.bVisible = FALSE;
	SetConsoleCursorInfo(hConsole, &cursorInfo);
	for (int i = 0;i < lengthofside;i++) {
		map[i][0] = map[lengthofside - 1][i] = map[0][i] = map[i][lengthofside - 1] = -1;
		gotoxy(i + 1, 1);
		std::cout << "■";
		gotoxy(i + 1, lengthofside*2-1);
		std::cout << "■";
		gotoxy(1, i*2 + 1);
		std::cout << "■";
		gotoxy(lengthofside, i*2 + 1);
		std::cout << "■";
	}
	for (int i = 4;i <= 8;i++) {
		for(int j = 4;j <= 8;j++) {
			map[i][j] = -1;
			gotoxy(i + 1, j * 2 + 1);
			std::cout << "■";
		}
	}
	for (int i = 4;i <= 8;i++) {
		for (int j = 20;j <= 24;j++) {
			map[i][j] = -1;
			gotoxy(i + 1, j * 2 + 1);
			std::cout << "■";
		}
	}
	for (int i = 20;i <= 24;i++) {
		for (int j = 4;j <= 8;j++) {
			map[i][j] = -1;
			gotoxy(i + 1, j * 2 + 1);
			std::cout << "■";
		}
	}
	for (int i = 20;i <= 24;i++) {
		for (int j = 20;j <= 24;j++) {
			map[i][j] = -1;
			gotoxy(i + 1, j * 2 + 1);
			std::cout << "■";
		}
	}
	for (int i = 12;i <= 16;i++) {
		for (int j = 12;j <= 16;j++) {
			map[i][j] = -1;
			gotoxy(i + 1, j * 2 + 1);
			std::cout << "■";
		}
	}
	place_food();
}

void drawgamescreen() {
	for (int i = 1;i < lengthofside-1;i++) {
		for (int j = 1;j < lengthofside-1;j++) {
			gotoxy(i+1, j * 2+1);
			if(map[i][j] == 1) {	
				setColor(4);
				std::cout << "▲";
				continue;
			}
			if (map[i][j] == 2) {
				setColor(2);
				std::cout << "●";
				continue;
			}
			if (map[i][j] == 3) {
				setColor(2);
				std::cout << "○";
				continue;
			}
			if (map[i][j] == -1)continue;
			std::cout << "  ";
		}
	}
	return;
}

void snake_move() {
	map[snake.front().x][snake.front().y] = 3;
	int new_x = snake.front().x, new_y = snake.front().y;
	switch (orientation) {
	case 1:
		new_x--;
		break;
	case 2:
		new_x++;
		break;
	case 3:
		new_y--;
		break;
	case 4:	
		new_y++;
		break;
	}
	if(map[new_x][new_y] == 3|| map[new_x][new_y] == -1) {
		game_over = 1;
		return;
	}
	if (map[new_x][new_y] == 1) {
		score += base_score;
		speed_change = min(1, speed_change + 1);
		setColor(4);
		gotoxy(4, lengthofside * 2 + 6);
		std::cout << "恭喜你，吃到了食物！";
		tip_interval = 12;
		place_food();
		setColor(11);
		gotoxy(6, lengthofside * 2 + 6);
		std::cout << "score:" << score;
	}
	else {
		switch (speed_change) {
		case 1:
			tip_interval--;
			break;
		case 0:
			tip_interval -= 2;
			break;
		case -1:
			tip_interval -= 4;
			break;
		}
		map[snake.back().x][snake.back().y] = 0;
		snake.pop_back();
	}
	if (tip_interval == 0) {
		setColor(15);
		gotoxy(4, lengthofside * 2 + 6);
		std::cout << "                                     ";
	}
	snake.push_front({ new_x,new_y });
	map[new_x][new_y] = 2;
}


void start_game() {
	init();
	while (1) {
		drawgamescreen();
		bool speed_has_change=0;
		for (int i = 1;i <= 10000;i++) {
			for (int i = 1;i <= refresh_interval;i++)++score;
			for (int i = 1;i <= refresh_interval;i++)--score;
			if (last_orient!=3 && GetAsyncKeyState('D') & 0x8000) {
				orientation = 4;
			}
			if (last_orient!=1 && GetAsyncKeyState('S') & 0x8000) {
				orientation = 2;
			}
			if (last_orient!=4 && GetAsyncKeyState('A') & 0x8000) {
				orientation = 3;
			}
			if (last_orient!=2 && GetAsyncKeyState('W') & 0x8000) {
				orientation = 1;
			}
			if (!speed_has_change && GetAsyncKeyState('Q') & 0x8000) {
				speed_change= min(1, speed_change+1);
				speed_has_change = 1;
			}
			if (!speed_has_change && GetAsyncKeyState('E') & 0x8000) {
				speed_change = max( - 1, speed_change - 1);
				speed_has_change = 1;
			}
			if (GetAsyncKeyState(VK_ESCAPE) & 0x8000) {
				return;
			}
		}
		last_orient = orientation;
		snake_move();
		if (game_over)break;
		setColor(2);
		gotoxy(2, lengthofside * 2 + 6);
		switch (speed_change) {
		case 1:
			refresh_interval = default_interval >> 1;
			base_score = 9;
			std::cout << "fast speed      ";
			break;
		case 0:
			refresh_interval = default_interval;
			base_score = 3;
			std::cout << "default speed   ";
			break;
		case -1:
			refresh_interval = default_interval << 1;
			base_score = 1;
			std::cout << "slow speed     ";
			break;
		}
	}
	return;
}